﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Infrastructure.ObjectModel;
using Infrastructure.ServiceInterfaces;
using B10_Ex02_Elad_034695114_Meyron_026607788;
using B10_Ex02_Elad_034695114_Meyron_026607788.ObjectModel;
using Microsoft.Xna.Framework.Graphics;
using Infrastructure.Managers;
using Microsoft.Xna.Framework.Input;

namespace B10_Ex02_EladLebovitch_034695114.ObjectModel
{
    public class GameManager : GameService
    {
        #region Consts
        private const int k_MotherShipInterval = 15000;
        private const int k_EnemyRows = 5;
        private const int k_EnemyCols = 9;
        private const int k_FirstPlayerNumber = 1;
        private const int k_SecondPlayerNumber = 2;
        private const int k_StartingSouls = 3;
        private const int k_BarriersCount = 4;
        #endregion

        #region Data members
        private double m_MotherShipTime;
        private EnemyMatrix m_EnemiesMat;
        private BarrierLine m_BarrierLine;
        private MotherShip m_CurrMothership;
        private HumanPlayer m_humPlayerOne;
        private HumanPlayer m_humPlayerTwo;
        private GameStatusDisplay m_gameDisplay;
        private ICollisionsManager m_MyCollisionDetector;
        private List<ObjectPair> m_arrBulletCollisions;

        public bool IsGameOver
        {
            get;
            set;
        }
        
        public GameManager(Game i_game)
            : base(i_game)
        {
        }

        #endregion

        #region Methods
        /// <summary>
        /// Init method
        /// </summary>
        public override void Initialize()
        {
            // Init stuff
            base.Initialize();
            this.IsGameOver = false;
            
            // Get collision detector
            m_MyCollisionDetector = this.Game.Services.GetService(typeof(ICollisionsManager)) as ICollisionsManager;

            // Set bullet collision keeper
            m_arrBulletCollisions =  new List<ObjectPair>();
            
            // Create game objcets
            m_EnemiesMat = new EnemyMatrix(this.Game, k_EnemyCols, k_EnemyRows);
            m_EnemiesMat.MatrixEnemyDied += new EnemyDestroyed(this.enemeyDestroyed);
            m_BarrierLine = new BarrierLine(this.Game, k_BarriersCount);
            
            // Create the players and space ship
            m_humPlayerOne = new HumanPlayer(this.Game, Keys.Left, Keys.Right, Keys.Enter,
                                           k_FirstPlayerNumber, k_FirstPlayerNumber - 1, true);
            m_humPlayerTwo = new HumanPlayer(this.Game, Keys.A, Keys.D, Keys.Space, 
                                           k_SecondPlayerNumber, k_SecondPlayerNumber - 1, false);
            InitPlayer(m_humPlayerOne);
            InitPlayer(m_humPlayerTwo);
         
            // Game status display
            m_gameDisplay = new GameStatusDisplay(this.Game, m_humPlayerOne, m_humPlayerTwo, Color.Blue,Color.Green);

            // Handle the mother ship appearence
            this.m_MotherShipTime = 0;
        }

        /// <summary>
        /// Sets the player init stuff
        /// </summary>
        /// <param name="io_humPlayer">the current player</param>
        private void InitPlayer(HumanPlayer io_humPlayer)
        {
            io_humPlayer.Souls = k_StartingSouls;
            io_humPlayer.GameScore = 0;
            io_humPlayer.PlayerIsDeadEvent += new EventHandler(humPlayer_PlayerIsDeadEvent);
        }

        /// <summary>
        /// What happens when a player is out of souls
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void humPlayer_PlayerIsDeadEvent(object sender, EventArgs e)
        {
            // Check if one of the players is still alive
            if (m_humPlayerOne.Souls <= 0 && m_humPlayerTwo.Souls <= 0)
            {
                gameOver();
            }
        }

        /// <summary>
        /// Handles checks of the matrix
        /// </summary>
        private void handleMatrix()
        {
            // if the matrix got lower then spaceship
            if (this.m_EnemiesMat.LowerBoundery >= this.m_humPlayerOne.PlayerShip.PositionOfOrigin.Y)
            {
                this.gameOver();    
            }
        }

        /// <summary>
        /// The mothership creation method
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void handleMotherShip(GameTime gameTime)
        {
            this.m_MotherShipTime += gameTime.ElapsedGameTime.TotalMilliseconds;

            // Create a new mother ship
            if (this.m_MotherShipTime >= k_MotherShipInterval)
            {
                // if there is the first ship, Register it
                if (this.m_CurrMothership == null)
                {
                    // Create and register new
                    this.m_CurrMothership = new MotherShip(this.Game);
                    this.m_MotherShipTime -= k_MotherShipInterval;
                    this.m_MyCollisionDetector.AddObjectToMonitor(this.m_CurrMothership);
                    this.m_CurrMothership.Destroyed += new EnemyDestroyed(enemeyDestroyed);
                }
                else
                {
                    this.m_CurrMothership.Initialize();
                }
            }
        }

        /// <summary>
        /// When an enemy is dead, if it's the last one then game over
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void enemeyDestroyed(object sender, EventArgs e)
        {
            // Check if this was the last enemy
            if (m_EnemiesMat.EnemiesList.Count <= 0)
            {
                gameOver();
            }
        }

        /// <summary>
        /// When we won or lost
        /// </summary>
        private void gameOver()
        {
            this.IsGameOver = true;
            string strWinner = string.Empty;

            // Check who one
            if (m_humPlayerOne.GameScore > m_humPlayerTwo.GameScore)
            {
                strWinner = "Player one WINS!";
            }
            else if (m_humPlayerOne.GameScore < m_humPlayerTwo.GameScore)
            {
                strWinner = "Player two WINS!";
            }
            else
            {
                strWinner = "It is a TIE!";
            }

            // Notfiy the user
            System.Windows.Forms.MessageBox.Show("Game Over. \n Player One Score: " + m_humPlayerOne.GameScore.ToString() +
                                                 "\n Player Two Score: " + m_humPlayerTwo.GameScore.ToString() +
                                                 "\n" + strWinner);
        }

        /// <summary>
        /// Update method for calcing the game
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Update(GameTime gameTime)
        {
            // Make sure there is a need for update
            if (!IsGameOver)
            {
                // Handle both componentes
                this.handleMotherShip(gameTime);
                this.handleMatrix();

                base.Update(gameTime);
            }
        }
        #endregion
    }
}
